package com.huawang.mdesign.model.service.util.mindmap;

import com.huawang.core.definition.mof.util.SnowflakeIdWorkerUtil;
import com.huawang.mdesign.model.service.constant.mindmap.MindMapEnum;
import com.huawang.mdesign.model.service.util.mindmap.xmind.Item;
import com.huawang.mdesign.model.service.util.mindmap.xmind.Root;
import com.huawang.mdesign.model.service.util.mindmap.xmind.RootTopic;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 纯文本解析类
 *
 * @author admin
 */
@Component
public class PlainTextUtil implements MindMap {

    public static final char TAB = '\t';

    public static final String ENTER = "\n";

    @Override
    public boolean support(@NotNull String sourceFile) {
        return StringUtils.isNotBlank(sourceFile) && sourceFile.endsWith(MindMapEnum.PLAIN_TEXT.getSuffix());
    }

    /**
     * 解析纯文本
     *
     * @param sourceFile 文本内容
     * @return 树型结构
     */
    @Override
    public @NotNull List<Root> read(@NotNull String sourceFile) {
        if (StringUtils.isBlank(sourceFile)) {
            return Collections.emptyList();
        }

        String[] lines = sourceFile.split(ENTER);
        List<Row> rows = new ArrayList<>();
        for (String line : lines) {
            if (StringUtils.isBlank(line)) {
                continue;
            }

            Row row = new Row();
            row.setId(SnowflakeIdWorkerUtil.getId());
            rows.add(row);

            if (line.startsWith(String.valueOf(TAB))) {
                char[] chars = line.toCharArray();
                int level = row.getLevel();
                for (char c : chars) {
                    if (c == TAB) {
                        ++level;
                    } else {
                        row.setLevel(level);
                        break;
                    }
                }
                int len = line.length();
                if (level < len) {
                    row.setTitle(line.substring(level, len));
                }
                setParent(row, rows);
            } else {
                row.setTitle(line);
            }
        }

        return getRoot(rows);
    }

    /**
     * 设置父节点
     *
     * @param row  当前节点
     * @param rows 当前节点之前的节点
     */
    private static void setParent(@NotNull Row row, @NotNull List<Row> rows) {
        for (int i = rows.size() - 1; i >= 0; --i) {
            if (rows.get(i).getLevel() == row.getLevel() - 1) {
                row.setParentId(rows.get(i).getId());
                break;
            }
        }
    }

    /**
     * 构建树型结构
     *
     * @param rows 所有节点
     * @return 树形结构
     */
    @NotNull
    private List<Root> getRoot(@NotNull List<Row> rows) {
        List<Root> res = new ArrayList<>();
        rows.stream()
                .filter(Objects::nonNull)
                .filter(e -> StringUtils.isBlank(e.getParentId()))
                .forEach(e -> {
                    Item root = new Item();
                    root.setId(e.getId());
                    root.setTitle(e.getTitle());
                    setChildren(rows, root);
                    res.add(item2Root(root));
                });
        return res;
    }

    /**
     * 设置子节点
     *
     * @param rows   节点集合
     * @param parent 父节点
     */
    private static void setChildren(@NotNull List<Row> rows, @NotNull Item parent) {
        List<Item> children = new ArrayList<>();
        for (Row e : rows) {
            if (Objects.equals(e.getParentId(), parent.getId())) {
                Item item = new Item();
                item.setId(e.getId());
                item.setTitle(e.getTitle());
                children.add(item);
                setChildren(rows, item);
            }
        }
        FreeMindUtil.setChildren(children, parent);
    }

    /**
     * 数据类型转化
     *
     * @param item 当前节点
     * @return 根节点
     */
    @NotNull
    private static Root item2Root(@NotNull Item item) {
        Root root = new Root();
        RootTopic rootTopic = new RootTopic();
        root.setRootTopic(rootTopic);

        rootTopic.setId(item.getId());
        rootTopic.setTitle(item.getTitle());
        rootTopic.setChildren(item.getChildren());
        return root;
    }

    @Data
    public static class Row {

        private String id;

        private String title;

        private int level;

        private String parentId;

    }
}
